Skip to content

Lazy neighborhood filter kernel compilation - #1708

Merged
erogluorhan merged 7 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/lazy_nb_kernels
Aug 31, 2026
Merged

Lazy neighborhood filter kernel compilation#1708
erogluorhan merged 7 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/lazy_nb_kernels

Conversation

@cmdupuis3

@cmdupuis3 cmdupuis3 commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Closes #1706

Overview

This PR should solve an issue introduced with PR #941, wherein the neighborhood filter gufunc-based kernels would compile eagerly, forcing a major slowdown of basic import uxarray imports, as well as creating threadpools that would eventually block safe forking that is needed in PR #1700.

The idea is to have lazy compilation of gufuncs introduced with neighborhood filters for performant reductions. This prevents the otherwise eager compilation of every one of these kernels upon import uxarray.

Combined, this PR and PR #1700 can bring the total benchmark suit runtime down to about half of the pre-neighborhood filters runtime of ~40min, yielding about 20min without neighborhood filter benchmarks and 26-40ish minutes with them.

On its own, this PR can at least mitigate some of the benchmark performance regression, on the order of about 30-50% or so.

PR Checklist

General

  • An issue is created and linked
  • Added appropriate labels (if your uxarray repo permissions allow it)
  • Filled out Overview and Expected Usage (if applicable) sections

Testing & Benchmarking

  • Adequate tests are created if there is new functionality
  • Tests are not too basic (such as simply calling a function and nothing else)
  • Tests cover all major paths in your new functions
  • If this PR could affect performance, ran ASV benchmarks and confirmed they show expected behavior (add a new benchmark if necessary)

Documentation

  • Docstrings have been added to all new functions
  • Docstrings have been updated with any function changes

AI Disclosure

AI Usage: Claude Opus 5

  • I take responsibility for all AI-generated content in my PR.
  • I have tested all AI-generated content in my PR.

@cmdupuis3
cmdupuis3 requested a review from Sevans711 August 25, 2026 20:34
@cmdupuis3 cmdupuis3 self-assigned this Aug 25, 2026
@cmdupuis3 cmdupuis3 added bug Something isn't working run-benchmark Run ASV benchmark workflow benchmarking Related to benchmarks, memory usage, and/or time profiling labels Aug 25, 2026
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [efaa5ca] After [716c115] Ratio Benchmark (Parameter)
- 53.6±1ms 40.6±2ms 0.76 bench_connectivity.Connectivity.time_node_face('120km')
- 405M 337M 0.83 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
- 435M 368M 0.85 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
- 407M 339M 0.83 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
- 406M 338M 0.83 face_bounds.FaceBoundsColdStartRss.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
- 7.05±0.02s 538±5ms 0.08 import.Imports.timeraw_import_uxarray
- 365M 293M 0.8 import.Imports.track_peakmem_import_uxarray
- 425M 357M 0.84 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 1)
- 425M 357M 0.84 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 2)
- 425M 357M 0.84 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('120km', 4)
- 408M 340M 0.83 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 1)
- 408M 340M 0.83 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 2)
- 409M 339M 0.83 mpas_ocean.CrossSectionsPeakMem.peakmem_const_lat('480km', 4)
- 420M 353M 0.84 mpas_ocean.GradientColdStartRss.peakmem_gradient('120km')
- 401M 334M 0.83 mpas_ocean.GradientColdStartRss.peakmem_gradient('480km')
- 34.0±0.9ms 29.6±0.8ms 0.87 mpas_ocean.NeighborhoodDask.time_mean('120km', 'grid_chunks')
- 9.35±0.5ms 7.04±0.1ms 0.75 mpas_ocean.NeighborhoodDask.time_mean('480km', 'grid_chunks')
- 6.66±0.9ms 4.97±0.1ms 0.75 mpas_ocean.NeighborhoodDask.time_mean('480km', 'time_chunks')
- 427M 359M 0.84 mpas_ocean.ZonalAveragePeakMem.peakmem_zonal_average('120km')
- 410M 342M 0.83 mpas_ocean.ZonalAveragePeakMem.peakmem_zonal_average('480km')

Benchmarks that have stayed the same:

Change Before [efaa5ca] After [716c115] Ratio Benchmark (Parameter)
103±2ms 102±2ms 0.99 bench_connectivity.Connectivity.time_edge_face('120km')
6.65±0.2ms 6.31±0.05ms 0.95 bench_connectivity.Connectivity.time_edge_face('480km')
102±1ms 96.6±2ms 0.95 bench_connectivity.Connectivity.time_edge_node('120km')
5.78±0.2ms 5.64±0.1ms 0.98 bench_connectivity.Connectivity.time_edge_node('480km')
103±1ms 98.9±2ms 0.96 bench_connectivity.Connectivity.time_face_edge('120km')
6.03±0.2ms 5.65±0.1ms 0.94 bench_connectivity.Connectivity.time_face_edge('480km')
437±5ms 437±4ms 1.00 bench_connectivity.Connectivity.time_face_face('120km')
27.2±0.5ms 27.5±0.4ms 1.01 bench_connectivity.Connectivity.time_face_face('480km')
44.8±3μs 40.8±1μs 0.91 bench_connectivity.Connectivity.time_face_node('120km')
41.6±2μs 39.7±4μs 0.95 bench_connectivity.Connectivity.time_face_node('480km')
245±5μs 254±7μs 1.04 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
203±5μs 192±8μs 0.95 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
99.5±2ms 100±3ms 1.01 bench_connectivity.Connectivity.time_node_edge('120km')
6.10±0.3ms 5.93±0.1ms 0.97 bench_connectivity.Connectivity.time_node_edge('480km')
2.91±0.07ms 2.64±0.3ms ~0.91 bench_connectivity.Connectivity.time_node_face('480km')
4.35±0.4ms 4.50±0.2ms 1.03 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
1.50±0.1ms 1.47±0.02ms 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
6.53±7s 5.61±8ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
1.19±0.02ms 1.14±0.04ms 0.96 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
57.3k 57.3k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
12.3k 12.3k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
123k 123k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
128 128 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.27M 1.27M 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
50.1k 50.1k 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
1.48M 1.48M 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
712 712 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
2.01M 2.02M 1.01 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.01M 2.03M 1.01 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.17M 2.19M 1.01 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
38.3k 38.3k 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
631±30ns 641±40ns 1.02 geometry_kernels.AccucrossKernels.time_accucross
1.36±0.01μs 1.40±0.05μs 1.03 geometry_kernels.AccucrossKernels.time_accucross_pair
255±10ns 250±7ns 0.98 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
250±10ns 245±5ns 0.98 geometry_kernels.EFTPrimitives.time_diff_of_products
221±10ns 220±4ns 1.00 geometry_kernels.EFTPrimitives.time_two_prod
221±4ns 220±0ns 1.00 geometry_kernels.EFTPrimitives.time_two_sum
831±20ns 817±5ns 0.98 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
636±30ns 591±10ns 0.93 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
1.06±0.03μs 1.06±0.04μs 1.00 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
1.79±0.05μs 1.75±0.03μs 0.98 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
721±100ns 676±20ns 0.94 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
1.83±0.07μs 1.79±0.03μs 0.98 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
23.8±1μs 22.7±0.4μs 0.96 geometry_kernels.OrientPredicates.time_on_minor_arc
426±9ns 471±30ns ~1.11 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
1.64±0.06ms 1.56±0.02ms 0.95 geometry_samebody.SameBodyConstLat.time_accux_dispatch
688±10μs 691±20μs 1.00 geometry_samebody.SameBodyConstLat.time_accux_kernel
1.10±0.01ms 1.10±0.01ms 1.00 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
90.3±1μs 89.2±1μs 0.99 geometry_samebody.SameBodyConstLat.time_fp64_kernel
failed failed n/a geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
failed failed n/a geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
failed failed n/a geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
failed failed n/a geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
1.41±0.09ms 1.45±0.02ms 1.03 mpas_ocean.CheckNorm.time_check_norm('120km')
1.12±0.04ms 1.13±0.02ms 1.01 mpas_ocean.CheckNorm.time_check_norm('480km')
392±6ms 405±8ms 1.04 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
24.4±1ms 25.1±0.7ms 1.03 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
402±10μs 407±5μs 1.01 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
344±4μs 332±10μs 0.96 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
2.62±0.07ms 2.63±0.06ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
2.13±0.02ms 2.14±0.02ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
69.6±0.2ms 70.5±1ms 1.01 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
6.50±0.1ms 7.05±0.4ms 1.08 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
12.9±0.07ms 13.0±0.3ms 1.01 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
6.65±0.05ms 6.80±0.1ms 1.02 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
531±10μs 541±10μs 1.02 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
316±2ms 319±5ms 1.01 mpas_ocean.CrossSections.time_const_lat('120km', 1)
153±2ms 163±3ms 1.07 mpas_ocean.CrossSections.time_const_lat('120km', 2)
82.1±2ms 84.1±1ms 1.02 mpas_ocean.CrossSections.time_const_lat('120km', 4)
275±3ms 276±7ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 1)
137±3ms 141±3ms 1.03 mpas_ocean.CrossSections.time_const_lat('480km', 2)
70.7±0.6ms 73.0±0.8ms 1.03 mpas_ocean.CrossSections.time_const_lat('480km', 4)
15.5±0.2ms 16.2±0.4ms 1.04 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
1.73±0.02ms 1.71±0.1ms 0.99 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
47.6±1ms 48.7±1ms 1.02 mpas_ocean.FaceAreas.time_face_areas('120km')
4.72±0.2ms 5.14±0.3ms 1.09 mpas_ocean.FaceAreas.time_face_areas('480km')
229k 229k 1.00 mpas_ocean.FaceAreas.track_nbytes_face_areas('120km')
14.3k 14.3k 1.00 mpas_ocean.FaceAreas.track_nbytes_face_areas('480km')
2.12M 2.12M 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('120km')
830k 836k 1.01 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
473±2ms 478±6ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
29.2±0.3ms 28.4±0.8ms 0.97 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
41.1±0.4ms 42.2±2ms 1.03 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
3.65±0.2ms 3.76±0.1ms 1.03 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
133±4ms 137±1ms 1.03 mpas_ocean.Gradient.time_gradient('120km')
9.00±0.2ms 9.55±0.2ms 1.06 mpas_ocean.Gradient.time_gradient('480km')
457k 457k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('120km')
28.7k 28.7k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('480km')
5.08M 5.08M 1.00 mpas_ocean.Gradient.track_peakmem_gradient('120km')
328k 328k 1.00 mpas_ocean.Gradient.track_peakmem_gradient('480km')
268±7μs 276±20μs 1.03 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
140±6μs 161±9μs ~1.15 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
418±10μs 462±30μs ~1.11 mpas_ocean.Integrate.time_integrate('120km')
18.4M 18.4M 1.00 mpas_ocean.Integrate.track_nbytes_integrate('120km')
1.2M 1.2M 1.00 mpas_ocean.Integrate.track_nbytes_integrate('480km')
108±3ms 107±3ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
103±1ms 106±1ms 1.03 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
105±2ms 105±3ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
8.50±0.1ms 9.13±0.3ms 1.07 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
8.05±0.1ms 8.53±0.07ms 1.06 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
8.54±0.4ms 8.72±0.3ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
169±2ms 169±1ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 1.0)
914±10ms 915±3ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 15.0)
352±3ms 355±5ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('120km', 5.0)
9.30±0.2ms 9.26±0.06ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('480km', 1.0)
18.1±0.1ms 17.9±0.4ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('480km', 15.0)
11.7±0.1ms 11.5±0.1ms 0.99 mpas_ocean.NeighborhoodBuild.time_build('480km', 5.0)
165±2ms 162±2ms 0.99 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 1.0)
895±10ms 894±10ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 15.0)
340±7ms 347±3ms 1.02 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 5.0)
8.85±0.3ms 9.08±0.09ms 1.03 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 1.0)
17.6±0.1ms 17.6±0.1ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 15.0)
11.3±0.1ms 11.4±0.2ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 5.0)
1.19 1.19 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('120km', 1.0)
612.76 612.76 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('120km', 15.0)
74.17 74.17 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('120km', 5.0)
1.0 1.0 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('480km', 1.0)
37.29 37.29 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('480km', 15.0)
6.57 6.57 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('480km', 5.0)
728k 728k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('120km', 1.0)
141M 141M 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('120km', 15.0)
17.4M 17.4M 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('120km', 5.0)
43k 43k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('480km', 1.0)
563k 563k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('480km', 15.0)
123k 123k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('480km', 5.0)
5.72M 5.72M 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('120km', 1.0)
145M 145M 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('120km', 15.0)
21.5M 21.5M 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('120km', 5.0)
362k 362k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 1.0)
825k 825k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 15.0)
384k 384k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 5.0)
13.4±0.5ms 13.6±0.2ms 1.02 mpas_ocean.NeighborhoodDask.time_mean('120km', 'numpy')
30.4±1ms 28.8±2ms 0.95 mpas_ocean.NeighborhoodDask.time_mean('120km', 'time_chunks')
344±9μs 349±10μs 1.02 mpas_ocean.NeighborhoodDask.time_mean('480km', 'numpy')
5.76M 5.76M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'grid_chunks')
2.75M 2.75M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'numpy')
5.69M 5.68M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'time_chunks')
687k 679k 0.99 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'grid_chunks')
177k 177k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'numpy')
543k 536k 0.99 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'time_chunks')
8.52±0.07s 8.55±0.07s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'mean')
9.07±0.01s 8.94±0.03s 0.99 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'median')
161±1ms 155±0.8ms 0.96 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'mean')
166±1ms 168±2ms 1.02 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'median')
937±20ms 919±20ms 0.98 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'mean')
1.08±0.01s 1.07±0.02s 0.99 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'median')
18.4±0.4ms 17.6±0.4ms 0.96 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'mean')
19.4±0.2ms 19.4±0.3ms 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'median')
22.8±0.5ms 21.7±0.4ms 0.95 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'mean')
166±5ms 167±1ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'median')
448±40μs 415±80μs 0.93 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'mean')
1.71±0.07ms 1.63±0.03ms 0.95 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'median')
239k 239k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('120km', 'mean')
245k 245k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('120km', 'median')
19.7k 19.4k 0.98 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'mean')
20.2k 19.9k 0.99 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'median')
269±10μs 236±40μs ~0.88 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
215±5μs 232±9μs 1.08 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
266±60μs 227±20μs ~0.85 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
220±6μs 188±10μs ~0.85 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
124±1ms 125±1ms 1.01 mpas_ocean.RemapDownsample.time_bilinear_remapping
121±2ms 123±1ms 1.02 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
9.68±0.1ms 10.2±0.2ms 1.05 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
606±8ms 610±10ms 1.01 mpas_ocean.RemapUpsample.time_bilinear_remapping
23.1±1ms 23.1±0.4ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
7.58±0.3ms 7.42±0.3ms 0.98 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
5.96±0.3ms 6.51±0.08ms 1.09 mpas_ocean.ZonalAverage.time_zonal_average('120km')
3.26±0.2ms 3.28±0.3ms 1.01 mpas_ocean.ZonalAverage.time_zonal_average('480km')
3.77±0.04ms 3.78±0.09ms 1.00 quad_hexagon.QuadHexagon.time_open_dataset
3.07±0.06ms 3.14±0.2ms 1.02 quad_hexagon.QuadHexagon.time_open_grid
408 408 1.00 quad_hexagon.QuadHexagon.track_nbytes_open_dataset
392 392 1.00 quad_hexagon.QuadHexagon.track_nbytes_open_grid
73.8k 73.5k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
72.7k 72.8k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_grid

Benchmarks that have got worse:

Change Before [efaa5ca] After [716c115] Ratio Benchmark (Parameter)
+ 749±20μs 827±10μs 1.11 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
+ 318±10μs 362±30μs 1.14 mpas_ocean.Integrate.time_integrate('480km')

@Sevans711 Sevans711 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you looking into this! Assuming you wanted me to give an initial review now because you requested review, but not 100% sure since it is still marked as draft.

The regression test is clever, and I confirmed it crashes on main. This should be one good way to guard against import uxarray slowdowns in the future!

I left inline comments about the caching. Basically, it feels strange to me to use functools.cache in this situation, and I think it leads to some more-complicated-than-necessary code logic at the kernel call sites. I think it would be easier to maintain/understand quickly in the future if using a single cache which directly contains the cached kernels themselves, instead of caching on a per-function basis. That might also help with introspection/debugging later if you ever want to quickly check which kernels have been compiled so far. For example, there could even be a test which asserts _NUMBA_KERNELS is empty after import uxarray.

Comment thread uxarray/grid/neighbors.py Outdated
Comment thread uxarray/grid/neighbors.py Outdated
@cmdupuis3
cmdupuis3 marked this pull request as ready for review August 26, 2026 19:16
@cmdupuis3 cmdupuis3 mentioned this pull request Aug 26, 2026
12 tasks
@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

pre-commit.ci autofix

@cmdupuis3
cmdupuis3 requested a review from dylannelson August 31, 2026 16:20

@Sevans711 Sevans711 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the factory pattern rework in defa8d6, I am happy with how this looks. The _make_kernel function itself looks a bit complicated but the docstring and comments clearly explain what is happening, and now it actually returns "a kernel function" instead of returning "a kernel factory which must be called to get the kernel function" so the way to use it is aligned with my intuitions based on the function names and documentation. I recommend merging to main!

@erogluorhan
erogluorhan self-requested a review August 31, 2026 21:19

@erogluorhan erogluorhan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me; thanks for the fixes!

@erogluorhan
erogluorhan merged commit e095af5 into UXARRAY:main Aug 31, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

benchmarking Related to benchmarks, memory usage, and/or time profiling bug Something isn't working run-benchmark Run ASV benchmark workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Neighborhood filter reductions are making uxarray imports slow

3 participants